﻿using System;
using System.Collections.Generic;
using FakeItEasy;
using FluentAssertions;
using Sidewinder.Core.Interfaces;
using Sidewinder.Core.Interfaces.Entities;
using Wolfpack.Contrib.Deployment;
using Wolfpack.Core.Interfaces.Entities;
using Wolfpack.Core.Notification.Filters.Request;
using Wolfpack.Core.Testing;
using Wolfpack.Core.Testing.Domains;
using Wolfpack.Core;
using System.Linq;

namespace Wolfpack.Contrib.Tests.Publishers.Deployment
{
    public abstract class DeploymentPublisherDomainBase<T> : SystemDomainBase
        where T: DeploymentConfig
    {
        public class BaseConfig
        {
            public const string NuGetPackageId = "TestPackage";
            public const string NuGetFeed = "http://some.nugetfeed.com";
            public const string TriggerHealthCheckId = "TriggerMessage";
            public const string DownloadFolder = "PackageDownload";
        }

        protected readonly NotificationEvent _triggerNotification;

        protected IPipelineStep<UpdaterContext> _updater;

        protected T _config;
        
        protected DeploymentPublisherDomainBase()
        {
            // message tag contains the name of the nuget package
            // property "Feed" contains the nuget feed
            // property "PreviousVersion" contains the existing version
            // property "NewVersion" contains the new version
            _triggerNotification = NotificationEventBuilder.From(
                new NotificationEventHealthCheck
                    {
                        CheckId = BaseConfig.TriggerHealthCheckId,
                        Result = true,
                        Tags = new List<string>()
                    }).Build();

            _triggerNotification.Tags.AddIfMissing(BaseConfig.NuGetPackageId); 
            TheUpdaterIndicatesUpdateAvailable();
        }

        protected void SetDeploymentBaseConfig(T config)
        {
            config.PackageId = BaseConfig.NuGetPackageId;
            config.Feed = BaseConfig.NuGetFeed;
            config.DownloadFolder = BaseConfig.DownloadFolder;
            config.TargetHealthCheckName = BaseConfig.TriggerHealthCheckId;

            if (_config == null)
                _config = config;
        }

        public void TheDownloadFolder(string folder)
        {
            _config.DownloadFolder = folder;
        }

        public void ThePublisherShouldOnlyPublishOnFailure()
        {
            _config.NotificationMode = FailureOnlyNotificationFilter.FilterName;
        }

        public void TheTriggerNotificationHasACriticalFailure()
        {
            _triggerNotification.CriticalFailure = true;
        }

        public void TheTriggerNotificationIndicatesFailure()
        {
            _triggerNotification.Result = false;
        }

        public void TheCheckNotificationShouldHaveProperty_WithValue_(string expectedKey, string expectedValue)
        {
            var notification = Agent.NotificationEvents.First(n => n.EventType == NotificationEventHealthCheck.EventTypeName);
            
            notification.Properties.ContainsKey(expectedKey).Should().BeTrue();
            notification.Properties[expectedKey].Should().Be(expectedValue);
        }

        public void TheCheckNotificationTagShouldBeTheSameAsTheTriggerMessageTag()
        {
            Agent.NotificationEvents.First(n => n.EventType == NotificationEventHealthCheck.EventTypeName)
                .Tags.Should().BeEquivalentTo(_triggerNotification.Tags);
        }

        //public void TheResultDataMessageShouldHaveTheDurationSet()
        //{
        //    Agent.NotificationEvents.First(n => n.EventType == NotificationEventHealthCheck.EventTypeName)
        //        .Duration > TimeSpan.Zero).Should().BeTrue();
        //}

        public void TheUpdaterIndicatesUpdateAvailable()
        {
            TheUpdaterReturns_(true);
        }

        public void TheUpdaterIndicatesNoUpdateAvailable()
        {
            TheUpdaterReturns_(false);
        }

        public void TheUpdaterShouldNotHaveBeenCalled()
        {
            A.CallTo(() => _updater.Execute(A<UpdaterContext>.Ignored)).MustNotHaveHappened();
        }

        private void TheUpdaterReturns_(bool result)
        {
            _updater = A.Fake<IPipelineStep<UpdaterContext>>();
            A.CallTo(() => _updater.Execute(A<UpdaterContext>.Ignored))
                .Invokes(call =>
                             {
                                 var context = (UpdaterContext) call.Arguments[0];
                                 context.Updates.Add(new UpdatedPackage
                                                         {
                                                             Target =
                                                                 context.Config.TargetPackages[BaseConfig.NuGetPackageId
                                                                 ],
                                                             NewVersion = new Version(9, 9, 9, 9)
                                                         });
                             })
                .Returns(result);
        }
    }
}